#!/usr/bin/env python

# A wrapper script that interfaces between MOC (Music on console) and
# lastfmsubmit.  The problem with just using OnSongChange is that it
# will be triggered even if you listen to only one second of a song.
# This script will wait for half the length of the track, checking
# whether MOC is still playing it, before submitting the track to
# last.fm.  This way, skipping through a list of tracks will not
# result in lots of tracks submitted.

#  To use, put this in your ~/.moc/config file:
# OnSongChange = "/path/to/moc_submit_lastfm --artist %a --title %t --length %d --album %r"

# Author: Luke Plant  < http://lukeplant.me.uk/ >
# License: public domain

# psi_tune function by Stjujckij Nickolaj

from datetime import datetime
from optparse import OptionParser
from subprocess import call, Popen, PIPE
import time

parser = OptionParser()
parser.add_option("-a", "--artist", dest="artist")
parser.add_option("-t", "--title", dest="title")
parser.add_option("-A", "--album", dest="album")
parser.add_option("-l", "--length", dest="length")
parser.add_option("-n", "--track", dest="track")

# Treating everything as bytestrings throughout seems to work OK even
# with non-ASCII characters in song titles etc (at least with a UTF-8
# locale).

def still_playing(artist, album, title):
    p = Popen(["mocp", "-i"], stdout=PIPE)
    out, err = p.communicate()
    lines = out.split("\n")
    for s in ["Artist: %s" % artist, "Album: %s" % album, "SongTitle: %s" % title]:
        if not s in lines:
            return False
    return True

def submit_to_lastfm(artist, album, title, length):
    args = ["/usr/lib/lastfmsubmitd/lastfmsubmit", "--artist", artist, "--title", title, "--length", length]
    if album is not None:
        args.extend(["--album", album])
    call(args)

def main():
    options, args = parser.parse_args()
    if any(not options.__dict__.get(k) for k in ["artist", "title", "length"]):
        print "All of artist, album, length must be specified"
        exit(1)
    if ":" in options.length:
        mins, secs = options.length.split(":")
        length = int(mins) * 60 + int(secs)
    else:
        length = int(options.length)
    # wait until song is half played
    wait = length/2

    start = datetime.now()
    while True:
        time.sleep(5)
        psi_tune(options)
        if not still_playing(options.artist, options.album, options.title):
            exit(1)
        if (datetime.now() - start).seconds > wait:
            submit_to_lastfm(options.artist, options.album, options.title, options.length)
            exit(0)

def psi_tune(options):
    PSIDATADIR = os.getenv('PSIDATADIR')
    if not PSIDATADIR:
        PSIDATADIR = os.getenv('HOME') + '/.psi/'
    tunefile = open(PSIDATADIR+'tune', 'w')
    tunefile.write('%s\n%s\n%s\n%s\n%s\n' % (options.title, options.artist, options.album, options.track, options.length))
    tunefile.close()

if __name__ == '__main__':
    import sys, os
    main()
